Skip to content

feat(v2): land agent-core-v2 engine and kap-server behind experimental flag#1441

Open
sailist wants to merge 563 commits into
mainfrom
kimi-code-v2
Open

feat(v2): land agent-core-v2 engine and kap-server behind experimental flag#1441
sailist wants to merge 563 commits into
mainfrom
kimi-code-v2

Conversation

@sailist

@sailist sailist commented Jul 6, 2026

Copy link
Copy Markdown
Collaborator

Related Issue

N/A — integration PR that lands the long-lived kimi-code-v2 branch; see Problem below.

Problem

The v2 line — the DI × Scope based agent-core-v2 engine, the kap-server that hosts it, and the minidb read model — has been built up on the long-lived kimi-code-v2 integration branch. This PR merges that branch into main.

The v2 engine and server are not the default runtime yet. Both the kimi -p prompt path and kimi server run route to v2 only when KIMI_CODE_EXPERIMENTAL_FLAG is set, and the v2 module graph is lazy-imported so it stays off the default path. With the flag unset, the CLI keeps the v1 engine and @moonshot-ai/server.

What changed

Scope: 1,207 files, +192,653 / −285. The bulk is three new packages; everything else is CLI wiring, e2e coverage, skills, and small v1 touch-ups.

1. agent-core-v2: the new DI × Scope engine (packages/agent-core-v2, +146k, 872 files)

  • New agent-core-v2 package: a DI scope engine with an explicit agent / session lifecycle.
  • Wire/op state engine with derived wire models and ReplayTimelineModel; IEventBus and Op.toEvent alongside wire.signal; context writes routed through ops and declared tool delivery.
  • Per-agent wire records (wire.jsonl); flattened agent hierarchy with swarm lifted to session.
  • Execution environment reorganized into separate filesystem / process / tool domains.
  • Goal mode: core goal workflow, budget enforcement, and per-turn goal injection.
  • Model layer: Model god-object and protocol domains; kosong vendored as the internal llmProtocol/kosong implementation (drops the @moonshot-ai/kosong and @moonshot-ai/kaos dependencies).
  • Built-in tools registered via DI / contributions, plugin management, session subagent host + Agent tool, shared rg locator/runner, AGENTS.md hierarchy loading.

2. kap-server: the v2 server (packages/kap-server, +26k, 139 files)

  • New @moonshot-ai/kap-server package — the Kimi Code server backed by agent-core-v2 (codenamed "server-v2").
  • Hosts agent-core-v2 sessions over REST (/api/v1, ~25 route modules) and WebSocket (/api/v1/ws with seq/epoch watermark and resync), and serves the web assets.
  • Auth and request-security hardening, /openapi.json via @fastify/swagger, and v2 session export (diagnostic zip archives).
  • v1 parity fixes carried along: broadcast interaction question / approval events, honor the before_id pagination cursor, treat loopback origins as same-origin for WS upgrade, and align MCP media output with v1.

3. minidb: embedded read model (packages/minidb, +13k, 77 files)

  • New @moonshot-ai/minidb package — a pure-Node.js embedded KV database (Redis-style in-memory KV with SQLite-style WAL/snapshot persistence, secondary indexes, TTL), used as the session-index read model.

4. CLI wiring (apps/kimi-code, +762, 19 files)

  • kimi -p and kimi server run select v2 vs. v1 via KIMI_CODE_EXPERIMENTAL_FLAG (lazy import); v1 stays the default.
  • Add the v2 harness adapters (cli/v2/*) and the prompt-session abstraction shared by both engines; update TUI adapters to handle v2 events.

5. Tooling, e2e and docs

  • packages/server-e2e: typed v2 ServerClient SDK with a drift test and e2e coverage.
  • .agents/skills: add the agent-core-dev and write-tests skills plus other skill updates; add the dependency-graph dev viewer.
  • GOAL.md: design doc for the goal-mode feature split.
  • Minor: packages/protocol, packages/acp-adapter, packages/agent-core, packages/server, packages/node-sdk, apps/kimi-web, the hash-imports build loaders, flake.nix, and changesets.

Checklist

  • I have read the CONTRIBUTING document.
  • I have linked a related issue, or explained the problem above.
  • I have added tests that prove my feature works.
  • Ran gen-changesets skill, or this PR needs no changeset.
  • Ran gen-docs skill, or this PR needs no doc update.

@changeset-bot

changeset-bot Bot commented Jul 6, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: f8ebe5b

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 6 packages
Name Type
@moonshot-ai/kimi-code Minor
@moonshot-ai/agent-core-v2 Minor
@moonshot-ai/protocol Minor
@moonshot-ai/kap-server Patch
@moonshot-ai/agent-core Patch
@moonshot-ai/server Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fbb4a3a0c6

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +239 to +240
const session = this.opts.core.accessor.get(ISessionLifecycleService).get(sessionId);
if (session === undefined) return undefined;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Resume cold sessions before accepting WS subscriptions

When a client reconnects to a session that exists only on disk, such as after a server-v2 restart, the default snapshot path can succeed via the disk reader without materializing the session in ISessionLifecycleService. The following /api/v1/ws subscribe then calls ensureState, but this get() only checks live sessions and returns undefined, so the subscribe ack reports not_found and the socket is never registered; if a later prompt request resumes the session, that client still receives no live turn events. Use resume() here or otherwise create a broadcaster state for cold persisted sessions before returning false.

Useful? React with 👍 / 👎.

Comment on lines +1011 to +1015
'file.not_found',
'file.too_large',
'fs.path_not_found',
'fs.permission_denied',
'validation.failed',

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep the Kimi error schema exhaustive

The KimiErrorCode union above includes additional codes such as prompt.not_found, session.busy, fs.path_escapes, fs.is_directory, fs.is_binary, fs.too_large, fs.already_exists, fs.too_many_results, fs.grep_timeout, and fs.git_unavailable, but this runtime z.enum omits them. Any error or turn.ended.error payload carrying one of those valid codes from agent-core-v2 will fail eventSchema / sessionEventMessageSchema validation even though the TypeScript type says it is valid, so add the missing literals or derive the schema from a single source.

Useful? React with 👍 / 👎.

@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

❌ Nix build failed

Hash mismatch in pnpmDeps:

Hash
specified sha256-iBk+TV+rIhmd7bYnVFbW3kTGltojJl3pL2hhmsGO+Fk=
got sha256-Z3daIqAm/BikwRSMXydiorikn5PMsxvWtB07SujJYzQ=

Please update flake.nix with the got hash.

7Sageer and others added 26 commits July 7, 2026 13:39
When the Kimi OAuth toolkit short-circuits via its `ensureFresh` fast path (the cached refresh token is still usable), `toolkit.login` resolves without firing `onDeviceCode`. The v2 `OAuthService.startLogin` previously rejected in this case, so `POST /api/v1/oauth/login` returned a 500 that the web client swallowed and mislabeled as "current daemon does not support login". CLI-authenticated users could not (re)enter the v2 daemon through the web UI.

Treat that path as already authenticated: provision the managed provider (idempotent), refresh OAuth provider models so `defaultModel` is seeded (`/auth` then reports ready, matching v1 parity), and return a new `status: 'authenticated'` `OAuthFlowStart` variant so the web LoginDialog can skip the device-code UI entirely instead of falling into its catch-all "unsupported daemon" state.

The protocol `OAuthFlowStart` schema is now a discriminated union on `status`; kimi-web's wire / composable / LoginDialog types are updated to handle the new `authenticated` branch.

Tests: updated the v2 OAuthService test that previously asserted the buggy rejection to instead assert the fast path returns authenticated and provisions the provider.
Move MicroCompactionEffect next to the service that produces it, and derive MicroCompactionConfig from the single zod schema in configSection.ts so the section schema and the runtime config type no longer drift.
Run SubagentStart/SubagentStop and SessionStart/SessionEnd external hooks by observing hook slots instead of being invoked directly, matching the other external-hook observers.

- Add Agent-scoped IAgentRunHooksService hosting onWillStartAgentTask / onDidStopAgentTask; mirrorAgentRun runs those slots rather than calling IAgentExternalHooksService directly.
- AgentExternalHooksService registers on those slots to emit SubagentStart/SubagentStop; drop runAgentTaskStart/notifyAgentTaskStop from its public interface.
- Add Session-scoped ISessionExternalHooksService. ISessionLifecycleService gains onDidCreateSession / onWillCloseSession slots announcing source/reason for create, resume, fork, close, archive.
- Move externalHooks from L5 to L6 in check-domain-layers.mjs, update the DI dependency map, and drop now-dead Hooks/OrderedHookSlot/@IAgentTurnService imports.
…fresh

OAuthService.invalidateFlows previously cleared every in-flight device-code login on any provider config change. Startup-time model catalog refreshes rewrite the providers section without changing the OAuth provider itself, which aborted the active login and left the web login dialog stuck polling an empty flow after the user authorized in the browser.

Scope invalidation to providers that were removed or had their config changed, so an in-flight login for an unaffected provider completes normally.
Context injections can now return either plain reminder text or pre-built content parts, with turn-boundary state exposed to providers instead of the cadence option.
Replace the standalone HookEngine class with an App-scope IExternalHooksRunnerService that owns loading (config + plugin.enabledHooks()) and matching/running hooks. The Agent- and Session-scope external-hooks adapters now just observe their hook slots and inject the shared runner, so the duplicated per-adapter engine lifecycle (loadDynamicHooks / reload / ready gating / plugin.onDidReload) goes away.

- Add src/app/externalHooksRunner/ with the contract, App-scope impl, and a pure runner module (indexHooks / runMatchedHooks / blockDecision).
- Drop public HookEngine, HookEngineTriggerArgs, HookEngineOptions, and the ExternalHooksServiceOptions escape hatch; move HookEngine run/match logic into the runner.
- Register externalHooksRunner at L6 and export it from the package index.
- Migrate tests to a real runner built by makeHookRunner() and the externalHookServices() harness override; split engine.test.ts traits into externalHookRunner.test.ts.
IAgentContextSizeService.getStatus() becomes get(start?, end?) returning { size, measured, estimated } where size = measured + estimated. start/end follow Array.prototype.slice semantics (default whole context, negative indices count from the end, inverted range is empty). Update consumers, the context:status action binding, tests, and the edge-exposure cheatsheet.
…imports

- delete per-directory index.ts barrel files across src/ submodules
- update src and test imports to reference concrete module files directly
- rename a few index.ts entry files to named modules (migration.ts, providers.ts, builtin.ts)
- rewire src/index.ts to export from concrete modules instead of directory barrels
- add patch changeset noting the production-build fix
- rename packages/server-v2 to packages/kap-server and update every
  @moonshot-ai/server-v2 reference across apps, packages, flake.nix,
  and build scripts
- remove the experimental `kimi v2` CLI prefix and its tests from the
  apps/kimi-code main entry
- add legacy BackgroundTask protocol types and the `blocked` turn
  interrupt reason for cross-engine compatibility
@pkg-pr-new

pkg-pr-new Bot commented Jul 7, 2026

Copy link
Copy Markdown
pnpm dlx https://pkg.pr.new/@moonshot-ai/kimi-code@9f1827e
npx https://pkg.pr.new/@moonshot-ai/kimi-code@9f1827e

commit: 9f1827e

kermanx and others added 30 commits July 9, 2026 17:35
- add `activity` domain: `IAgentActivityService` (Agent turn lane machine),
  `ISessionActivityKernel` (Session admission, PR1 placeholder), and the
  `ActivityLease` that owns the turn `AbortSignal`
- turnService launches and cancels through the kernel lease; `Turn` now
  exposes `signal` instead of `abortController`
- agentLifecycle.remove drives `beginDisposal`/`settled` and waits for the
  in-flight turn to drain before releasing the agent scope
- add `activity.*` error codes; deprecate `turn.agent_busy` in favor of
  `activity.agent_busy`
These four legacy session actions were thin delegations to the native v2
services (ISessionLifecycleService.fork/archive,
IAgentFullCompactionService.begin, IAgentRPCService.cancel) with no v1-only
projection to centralize. Drop them from ISessionLegacyService and call the
native services directly from the kap-server sessions route. updateProfile,
createChild, listChildren, undo and status stay in the adapter since they
carry real v1 adaptation logic.
- add native v2 print runner (v2/run-v2-print.ts) that consumes agent-core-v2
  DI services and awaits Turn.result directly
- extract shared print-mode rendering into prompt-render.ts for v1 and v2
- remove the V2PromptHarness/V2Session shim and v2->v1 event translation
- decouple initializeCliTelemetry from PromptHarness (homeDir/auth/track)
- add IAgentPromptLegacyService.submitAndSettle for authoritative completion
- make IAgentPromptService.undo throw session.undo_unavailable with a structured
  reason; move the precheck into contextMemory
- add ISessionLifecycleService.createChild (fork + child markers) and
  ISessionIndex.list({ childOf })
- slim ISessionLegacyService to updateProfile/status (drop createChild,
  listChildren, undo)
- rewire kap-server session routes to the native services and map
  SESSION_UNDO_UNAVAILABLE
- run-v2-print: use core ITelemetryService + CloudAppender instead of
  kimi-telemetry; remove kimi-code-sdk import (auth via IOAuthToolkit,
  config path from bootstrap, hook result via structural type)
- prompt-render: replace SDK HookResultEvent with a structural type so
  the shared renderer does not depend on the v1 SDK event shape
- telemetry: revert initializeCliTelemetry to its original signature now
  that v2 no longer calls it; keep v1 callers and assertions untouched
- update run-prompt and v2-run-print tests for the new wiring
- implement SessionActivityKernel lane machine (restoring→active⇄quiescing→closing→disposed) with admission table, atomic quiesce+drain, beginClosing/settled, markActive
- start AgentActivityService lane at initializing; add markReady driven by agentLifecycle.create after bootstrap
- project LaneModel + EventBus facts into structured AgentActivitySnapshot (ActivityModel / setActivitySnapshot Op) with pending-approval and active-tool-call sets; emit agent.activity.updated
- add IAgentTurnService.launchWithLease; goal continuation acquires the lane before appending its prompt
- resolve pending interactions on turn.ended to avoid stranded awaiting_approval
- fullCompaction registers a background activity and checks the activity lane
- extract contextMemory publishSplice / isFullyUndoable / recoverFoldedLength helpers
- kap-server: map activity snapshot into legacy status and sessionEventBroadcaster
- add KIMI_PRINT_V2_ENV / isPrintV2Enabled so `kimi -p` routes to the
  native agent-core-v2 runner through its own switch
- keep `kimi server run` server-v2 routing on isKimiV2Enabled
  (KIMI_CODE_EXPERIMENTAL_FLAG), decoupling the two
- update print-mode tests and comments to reference the new switch
- resolve the effective `-p` format via resolveOutputFormat: the
  --output-format flag wins, then KIMI_MODEL_OUTPUT_FORMAT (prompt mode
  only), then text
- ignore the env outside prompt mode and reject invalid values eagerly
  through the friendly validation path
- apply the resolver on both the v1 and v2 print runners
Drop the KIMI_CRON_NO_JITTER / KIMI_CRON_NO_STALE notes from the
CronCreate and CronList descriptions and the MAX_SKILL_QUERY_DEPTH
sentence from the Skill description, matching agent-core (v1) where
these were trimmed from the model-facing text in #1102. Code behavior
is unchanged; the env bypasses and the depth cap still exist in both
implementations. ULID/8-hex wording is left as-is for now.
CronDelete and CronList descriptions now describe the task id as a ULID
only, removing the "(or legacy 8-hex)" qualifier from the model-facing
text. Code and tests are unchanged.
Move every file under test/ so its path mirrors the corresponding file
under src/ one-to-one (agent/, session/, app/, os/, persistence/,
_base/, activity/, wire/), and rename test files to match the basename
of the source file they cover. Test-only infrastructure with no src
counterpart (harness, snapshot, lint, dep-graph, tools/fixtures) stays
at the top level.

Rewrite imports after the move: src references use the #/ alias, while
test-to-test and cross-package relative imports are recomputed for the
new locations. No behavior changes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants